package drds.global_transaction.api.message_codec;

import drds.common.Log;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;

@Slf4j
public abstract class Message implements IMessageCodec, Serializable
{// the full name is MessageCodeC

	//
	public static final int $512 = 512;
	public static final int $1024 = 1024;
	//
	public static final short register_transaction_manager_request_message = 1;
	public static final short register_transaction_manager_response_message = 2;
	//
	public static final short register_resource_manager_request_message = 3;
	public static final short register_resource_manager_response_message = 4;
	//
	public static final short global_transaction_begin_request_message = 11;
	public static final short global_transaction_begin_response_message = 12;
	//
	public static final short global_transaction_commit_request_message = 13;
	public static final short global_transaction_commit_response_message = 14;
	//
	public static final short global_transaction_rollback_request_message = 15;
	public static final short global_transaction_rollback_response_message = 16;
	//
	public static final short global_transaction_status_report_request_message = 17;
	public static final short global_transaction_status_report_response_message = 18;
	//
	public static final short global_transaction_lock_record_ids_check_request_message = 19;
	public static final short global_transaction_lock_record_ids_check_response_message = 20;
	//
	//
	public static final short branch_transaction_register_request_message = 51;
	public static final short branch_transaction_register_response_message = 52;
	//
	public static final short branch_transaction_commit_request_message = 53;
	public static final short branch_transaction_commit_response_message = 54;
	//
	public static final short branch_transaction_rollback_request_message = 55;
	public static final short branch_transaction_rollback_response_message = 56;
	//
	public static final short branch_transaction_status_report_request_message = 57;
	public static final short branch_transaction_status_report_response_message = 58;
	//
	//
	public static final short type_request_messages = 101;
	public static final short type_response_messages = 102;

	//
	protected static final Charset UTF8 = Charset.forName("utf-8");
	private static final long serialVersionUID = 1l;

	public static int bytesToInt(byte[] bytes, int offset)
	{
		int ret = 0;
		for (int i = 0; i < 4 && i + offset < bytes.length; i++)
		{
			ret <<= 8;
			ret |= (int) bytes[i + offset] & 0xFF;
		}
		return ret;
	}

	public static void intToBytes(int $int, byte[] bytes, int offset)
	{
		bytes[offset] = (byte) (($int >> 24) & 0xFF);
		bytes[offset + 1] = (byte) (($int >> 16) & 0xFF);
		bytes[offset + 2] = (byte) (($int >> 8) & 0xFF);
		bytes[offset + 3] = (byte) ($int & 0xFF);
	}

	// public ByteBuffer byteBuffer = null;// 512 子类可以对该字段进行覆盖,但必须在encode方法里面进行覆盖
	// 为什么不选择构造函数和成员变量的模式,因为以成员变量的形式会出现数据被莫名的线程乱写的问题
	public ByteBuffer createByteBuffer()
	{// 默认是512字节,子类可以对该数字进行修改
		ByteBuffer byteBuffer = ByteBuffer.allocate($512);
		Log.output(log, byteBuffer.hashCode() + " " + byteBuffer.position() + " " + this.getClass().getSimpleName());
		return byteBuffer;
	}

	public ByteBuffer createByteBuffer(int byteBufferSize)
	{
		if (byteBufferSize < $512)
		{
			throw new IllegalArgumentException("byteBufferSize必须大于等于512");
		}
		if (byteBufferSize % $512 != 0)
		{
			throw new IllegalArgumentException("byteBufferSize必须是512的倍数");
		}
		ByteBuffer byteBuffer = ByteBuffer.allocate(byteBufferSize);
		Log.output(log, byteBuffer.hashCode() + " " + byteBuffer.position() + " " + this.getClass().getSimpleName());
		return byteBuffer;
	}

	public boolean encode = false;

	// 因为代码格式化-这样便于统一风格，代码上面先解码在编码 这边便于确定是否Ok,解码只有一个方法,编码存在几个方法.
	// 解码

	// 编码
	public byte[] encode()
	{
		ByteBuffer byteBuffer = putBytesToByteBuffer();
		return flipAndToBytes(byteBuffer);
	}

	public ByteBuffer putBytesToByteBuffer()
	{
		// do nothing
		return null;
	}

	public byte[] flipAndToBytes(ByteBuffer byteBuffer)
	{
		if (!encode)
		{
			return null;
		} else
		{
			byteBuffer.flip();
			byte[] bytes = new byte[byteBuffer.limit()];
			byteBuffer.get(bytes);
			byteBuffer.clear();
			// get bytes from byteBuffer
			return bytes;
		}

	}

	/**
	 * 采用父类标记原则 这样的好处只需要一处进行标记.为什么这么设计,因为子类可能复写 public byte[]
	 * encode()方法,如果该方法被复写那么需要自己的编码处理模式
	 */
	public void markAsEncode()
	{
		encode = true;
	}
	//

	/**
	 * @return 这必须是false
	 */
	@Override
	public boolean decode(ByteBuf byteBuf)
	{
		return false;
	}

	public void decode(ByteBuffer byteBuffer)
	{

	}
}
